package com.skp.shaphan.actions;

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

import com.skp.job.ProjectJobException;
import com.skp.shaphan.ShaphanApp;
import com.skp.shaphan.clipboard.HtmlSelection;
import com.skp.shaphan.clipboard.RtfSelection;
import com.skp.shaphan.io.ExportDataWriter;
import com.skp.shaphan.io.HtmlDataWriter;
import com.skp.shaphan.io.InsertDataWriter;
import com.skp.shaphan.io.JSONDataWriter;
import com.skp.shaphan.io.RtfDataWriter;
import com.skp.shaphan.io.TabDelimitedDataWriter;
import com.skp.shaphan.ui.results.IResultPane;
import com.skp.shaphan.ui.results.ResultPane;

/**
 * Exports data from a ResultSet.
 * 
 * Designed as a thread to run the in the background.
 * 
 * @author Stephen Phillips
 *
 */
public class ExportDataAction extends Thread {
	/**
	 * Export destination -- to the clipboard
	 */
	public static final int EXPORT_TYPE_CLIPBOARD = 1;
	/**
	 * Export destination -- to a file
	 */
	public static final int EXPORT_TYPE_FILE = 2;
	/**
	 * Output format -- tab delimited file
	 */
	public static final int FORMAT_TAB_DELIMITED = 1;
	/**
	 * Output format -- SQL Insert Statements
	 */
	public static final int FORMAT_SQL_INSERT= 3;
	/**
-	 * Output format -- JSON
	 */
	public static final int FORMAT_JSON = 5;
	/**
	 * Output format -- HTML
	 */
	public static final int FORMAT_HTML = 2;
	/**
	 * Output format -- RTF
	 */
	public static final int FORMAT_RTF = 4;
	/**
	 * Export destination type.  At the moment, it should either be clipboard or tab delimited.
	 */
	private int exportType = EXPORT_TYPE_CLIPBOARD;
	/**
	 * The path to the file where the data will go when exported.
	 */
	private String exportPath = "";
	/**
	 * Whether or not to use the field names as a heading
	 */
	private boolean includeHeadings;
	/**
	 * The output format.  Either tab delimited or HTML.
	 */
	private int format = FORMAT_TAB_DELIMITED;
	/**
	 * Results are printed to this print writer.  The print writer is hooked to
	 * either a file to output to a file or to a StringWriter to gather to send
	 * to the clipboard.
	 */
	private ExportDataWriter pw;
	
	/**
	 * The main processing for exporting the data
	 */
	@Override
	public void run() {
		System.out.println("exporting...");
		IResultPane resultPane = ShaphanApp.getMainWindow().getResultPane();
		String sqlStatement = resultPane.getCurrentSQLStatement();
		try {
			ResultSet results = buildResults(resultPane.getResultSet().getStatement().getConnection(), sqlStatement);
			createPrintWriter();
			printResults(results);
			finishIt();
		} catch (SQLException e1) {
			(new ProjectJobException(e1)).displayException();
		} catch (FileNotFoundException e1) {
			(new ProjectJobException(e1)).displayException();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * The creates the ResultSet -- executes teh SQL statement
	 * @param conn  The connection to the database where the SQL should run
	 * @param sql   The SQL statement to run
	 * @return
	 * @throws SQLException
	 */
	private ResultSet buildResults(Connection conn, String sql) throws SQLException {
		System.out.println("building results...");
		PreparedStatement st = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
		System.out.println("prepared statement...");
		ResultSet results = st.executeQuery();
		System.out.println("results complete...");
		return results;
	}
	
	/**
	 * Creates the print writer based on the type of format chosen.
	 * @throws IOException 
	 */
	private void createPrintWriter() throws IOException {
		if(format == FORMAT_RTF) {
			pw = new RtfDataWriter();
		} else if(format == FORMAT_HTML) {
			pw = new HtmlDataWriter();
		} else if(format == FORMAT_TAB_DELIMITED){
			pw = new TabDelimitedDataWriter();
		} else if(format == FORMAT_SQL_INSERT) {
			pw = new InsertDataWriter();
		} else if(format == FORMAT_JSON) {
			pw = new JSONDataWriter();
		}
		if(exportType == EXPORT_TYPE_FILE) {
			File outputFile = new File(exportPath);
			pw.setOutputFile(outputFile);
		}
	}
	
	/**
	 * Finishes the export process.  For the clipboard output, the data must
	 * be copied to the clipboard.
	 * @throws IOException 
	 */
	private void finishIt() throws IOException {
		// close the print writer
		pw.close();
		if(exportType == EXPORT_TYPE_CLIPBOARD) {
			Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
			Transferable contents = null;
			if(format == FORMAT_TAB_DELIMITED || format == FORMAT_SQL_INSERT || format == FORMAT_JSON) {
				contents = new StringSelection(pw.getData());
			}
			if(format == FORMAT_HTML) {
				contents = new HtmlSelection(pw.getData());
			}
			if(format == FORMAT_RTF) {
				contents = new RtfSelection(pw.getData());
			}
			clipboard.setContents(contents, ShaphanApp.getMainWindow().getClipboard());
		}
		if(exportType == EXPORT_TYPE_FILE) {
			// nothing additional needed
		}
	}
	
	/**
	 * Reads the data from the ResultSet and writes it to the PrintWriter.
	 * @param rs  The data to export/print
	 * @throws SQLException
	 * @throws IOException 
	 */
	private void printResults(ResultSet rs) throws SQLException, IOException {
		System.out.println("Printing results with..." + pw.getClass().getName());
		ResultSetMetaData meta = rs.getMetaData();
		pw.setMetaData(meta);
		if(includeHeadings) {
			for(int x=1; x<=meta.getColumnCount(); x++) {
				pw.writeHeadingCell(meta.getColumnLabel(x));
			}
			pw.finishHeadings();
		}
		boolean color = false;
		while(rs.next()) {
			pw.writeNewRow();
			for(int x=1; x<=meta.getColumnCount(); x++) {
				pw.writeCell(rs.getObject(x), x);
			}
			pw.closeRow();
			color = !color;
		}
		Statement st = rs.getStatement();
		rs.close();
		st.close();
	}
	
	/**
	 * The destination of the export data
	 * @return
	 */
	public int getExportType() {
		return exportType;
	}

	/**
	 * Determines the destination of the export data
	 *    EXPORT_TYPE_CLIPBOARD -- goes to clipboard
	 *    EXPORT_TYPE_FILE -- goes to a file
	 * @param exportType
	 */
	public void setExportType(int exportType) {
		this.exportType = exportType;
	}

	/**
	 * The file path were the data will be written
	 * @return
	 */
	public String getExportPath() {
		return exportPath;
	}

	/**
	 * Controls the path to the file where the data will be written
	 * @param exportPath
	 */
	public void setExportPath(String exportPath) {
		this.exportPath = exportPath;
	}

	/**
	 * Will the export include the field names as headings?
	 * @return
	 */
	public boolean isIncludeHeadings() {
		return includeHeadings;
	}

	/**
	 * Controls whether or not the export data includes the field names at the top
	 * @param includeHeadings
	 */
	public void setIncludeHeadings(boolean includeHeadings) {
		this.includeHeadings = includeHeadings;
	}
	
	public int getFormat() {
		return format;
	}

	public void setFormat(int format) {
		this.format = format;
	}
	

}
